import { Disposer, IDisposer } from "./07-Disposer";
import * as $array from "./06-Array";
import * as $async from "./08-AsyncPending";
import * as $type from "./02-Type";

// 定义事件对象的通用类型。
export type AMEvent<Target, T> = {
  [K in keyof T]: { type: K; target: Target } & T[K];
};
// 事件侦听器的通用接口。
export interface EventListener<T> {
  killed: boolean; // 是否被杀死
  once: boolean; // 一次性
  type: any; // 类型
  callback: any; // 回调
  context: any; // 上下文
  shouldClone: boolean; // 是否允许克隆
  dispatch: any; //
  disposer: IDisposer; // 派发
}

// 事件调度器
export class EventDispatcher<T> implements IDisposer {
  protected _listeners: Array<EventListener<T>>;
  protected _killed: Array<EventListener<T>>;
  protected _disabled: { [key in keyof T]?: number };
  protected _iterating: number;
  protected _enabled: boolean;
  protected _disposed: boolean;

  constructor() {
    this._listeners = [];
    this._killed = [];
    this._disabled = {};
    this._iterating = 0;
    this._enabled = true;
    this._disposed = false;
  }
  //   是否被销毁的状态
  public isDisposed(): boolean {
    return this._disposed;
  }
  //   销毁自身
  public dispose(): void {
    if (!this._disposed) {
      this._disposed = true;

      const listeners = this._listeners;
      this._iterating = 1;
      this._listeners = <any>null;
      this._disabled = <any>null;

      try {
        $array.each(listeners, (x) => {
          x.disposer.dispose();
        });
      } catch (error) {
      } finally {
        this._killed = <any>null;
        this._iterating = <any>null;
      }
    }
  }

  //   检查此特定事件调度器是否设置了侦听器。
  public hasListeners(): boolean {
    return this._listeners.length !== 0;
  }

  //   检查此特定事件调度器是否设置了特定类型侦听器。
  public hasListenersByType<Key extends keyof T>(type: Key): boolean {
    return $array.any(
      this._listeners,
      (x) => (x.type === null || x.type === type) && !x.killed
    );
  }

  //  设置为可用状态
  public enable(): void {
    this._enabled = true;
  }
  //   设置不可用状态
  public disable(): void {
    this._enabled = false;
  }

  public enableType<Key extends keyof T>(type: Key): void {
    delete this._disabled[type];
  }

  public disableType<Key extends keyof T>(
    type: Key,
    amount: number = Infinity
  ): void {
    this._disabled[type] = amount;
  }

  //   删除监听器
  protected _removeListener(listener: EventListener<T>): void {
    if (this._iterating === 0) {
      const index = this._listeners.indexOf(listener);
      if (index === -1) {
        throw new Error("无有效的监听器");
      }
      // 删除监听器
      this._listeners.splice(index, 1);
    } else {
      this._killed.push(listener);
    }
  }
  protected _eachListener(fn: (listener: EventListener<T>) => void): void {
    ++this._iterating;
    // console.log("_eachListener", this);
    try {
      $array.each(this._listeners, fn);
    } catch (error) {
    } finally {
      --this._iterating;
      if (this._iterating === 0 && this._killed.length !== 0) {
        $array.each(this._killed, (killed) => {
          this._removeListener(killed);
        });
        this._killed.length = 0;
      }
    }
  }
  //   根据某些参数删除现有监听器
  protected _removeExistingListener<A, B, Key extends keyof T>(
    once: boolean,
    type: Key | null,
    callback?: A,
    context?: B
  ): void {
    if (this._disposed) {
      throw new Error("无法移除一个已经被移除的监听器");
    }
    this._eachListener((info) => {
      if (
        info.once === once &&
        info.type === type &&
        (callback === null || info.callback === callback) &&
        info.context === context
      ) {
        info.disposer.dispose();
      }
    });
  }

  public isEnabled<Key extends keyof T>(type: Key): boolean {
    if (this._disposed) {
      throw new Error("无法移除一个已经被移除的监听器");
    }
    return (
      this._enabled &&
      this._listeners.length > 0 &&
      this.hasListenersByType(type) &&
      this._disabled[type] === null
    );
  }
  public has<C, Key extends keyof T>(
    type: Key,
    callback?: (this: C, event: T[Key]) => void,
    context?: C
  ): boolean {
    const index = $array.findIndex(this._listeners, (info) => {
      return (
        info.once !== true &&
        info.type === type &&
        (callback == null || info.callback === callback) &&
        info.context === context
      );
    });
    return index !== -1;
  }

  protected _shouldDispatch<Key extends keyof T>(type: Key): boolean {
    if (this._disposed) {
      throw new Error("事件调度者已被销毁");
    }
    console.log("判断是否可以被派发", { type }, this._disabled);
    const count = this._disabled[type];
    // console.log({ count });
    if (!$type.isNumber(count)) {
      return this._enabled;
    } else {
      if (count <= 1) {
        console.log("count <=1");
        delete this._disabled[type];
      } else {
        console.log("是数字，且 大于等于 -1");
        --this._disabled[type];
      }
    }
    console.log("不能被派发");
    return false;
  }
  // 无延迟的派发一次事件
  public dispatchImmediately<Key extends keyof T>(
    type: Key,
    event: T[Key]
  ): void {
    if (this._shouldDispatch(type)) {
      this._eachListener((listener) => {
        if (
          !listener.killed &&
          (listener.type === null || listener.type === type)
        ) {
          listener.dispatch(type, event);
        }
      });
    }
  }

  // 下一个周期要调度的事件
  public dispatch<Key extends keyof T>(type: Key, event: T[Key]): void {
    console.log("派发事件", { type, event });
    if (this._shouldDispatch(type)) {
      this._eachListener((listener) => {
        console.log("调用异步处理", listener);
        if (
          !listener.killed &&
          (listener.type === null || listener.type === type)
        ) {
          $async.whenIdle(() => {
            if (!listener.killed) {
              listener.dispatch(type, event);
            }
          });
        }
      });
    }
  }
  // 创建编译 返回 事件派发者[可被销毁]
  protected _on<A, B, Key extends keyof T>(
    once: boolean,
    type: Key | null,
    callback: A,
    context: B,
    shouldClone: boolean,
    dispatch: (type: Key, event: T[Key]) => void
  ): EventListener<T> {
    if (this._disposed) {
      throw new Error("事件派发者 已被销毁");
    }
    this._removeExistingListener(once, type, callback, context);

    const info: EventListener<T> = {
      type,
      callback,
      context,
      shouldClone,
      dispatch: <any>dispatch,
      killed: false,
      once,
      // 创建一个新的 销毁者 构造函数的 是销毁当前的
      disposer: new Disposer(() => {
        info.killed = true;
        this._removeListener(info);
      }),
    };
    // console.log("this,_on");
    this._listeners.push(info);
    console.log("监听者长度", this._listeners.length);
    return info;
  }

  // 创建一个可被任何事件使用的监听器
  public onAll<C, Key extends keyof T>(
    callback: (this: C, type: Key, event: T[Key]) => void,
    context?: C,
    shouldClone: boolean = true
  ): IDisposer {
    return this._on(
      false,
      null,
      callback,
      context,
      shouldClone,
      (type, event) => callback.call(context, type, event)
    ).disposer;
  }
  public on<C, Key extends keyof T>(
    type: Key,
    callback: (this: C, event: T[Key]) => void,
    context?: C,
    shouldClone: boolean = true
  ): IDisposer {
    return this._on(
      false,
      type,
      callback,
      context,
      shouldClone,
      (type, event) => callback.call(context, event)
    ).disposer;
  }

  public once<C, Key extends keyof T>(
    type: Key,
    callback: (this: C, event: T[Key]) => void,
    context?: C,
    shouldClone: boolean = true
  ): IDisposer {
    const x = this._on(
      true,
      type,
      callback,
      context,
      shouldClone,
      (type, event) => {
        x.disposer.dispose();
        callback.call(context, event);
      }
    );
    return x.disposer;
  }
  // *删除具有特定参数的事件侦听器。
  public off<C, Key extends keyof T>(
    type: Key,
    callback?: (this: C, event: T[Key]) => void,
    context?: C
  ): void {
    this._removeExistingListener(false, type, callback, context);
  }
  // *从另一个事件复制所有调度程序参数，包括侦听器 调度员。
  public copyFrom(source: this): void {
    if (this._disposed) {
      throw new Error("调度员已经被销毁");
    }
    if (source === this) {
      throw new Error("不能拷贝相同目标的事件调度员");
    }
    $array.each(source._listeners, (x) => {
      if (!x.killed && x.shouldClone) {
        if (x.type === null) {
          this.onAll(x.callback, x.context);
        } else if (x.once) {
          this.once(x.type, x.callback, x.context);
        } else {
          this.on(x.type, x.callback, x.context);
        }
      }
    });
  }
}
// *[[EventDispatcher]]的一个版本，用于为特定的 目标对象。

export class TargetedEventDispatcher<Target, T> extends EventDispatcher<T> {
  public target: Target;

  constructor(target: Target) {
    super();
    this.target = target;
  }
  // 重写copyFrom 方法
  public copyFrom(source: this): void {
    if (this._disposed) {
      throw new Error("事件调度员已被销毁");
    }
    if (source === this) {
      throw new Error("无法从同一目标事件调度程序复制");
    }

    $array.each(source._listeners, (x) => {
      if (x.context === source.target) {
        return;
      }
      if (!x.killed && x.shouldClone) {
        if (x.type === null) {
          this.onAll(x.callback, x.context);
        } else if (x.once) {
          this.once(x.type, x.callback, x.context);
        } else {
          this.on(x.type, x.callback, x.context);
        }
      }
    });
  }
}
